package com.huawei.admins.platform.gateway.core.component.router;

import com.huawei.admins.platform.gateway.core.component.cache.GatewayLocalCache;
import com.huawei.admins.platform.gateway.core.component.filter.GatewayFilter;
import com.huawei.admins.platform.gateway.core.component.filter.GatewayFilterAdapter;
import com.huawei.admins.platform.gateway.core.component.filter.GlobalFilter;
import jakarta.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.HandlerAdapter;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

public class RouteFilterHandlerAdapter implements HandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(RouteFilterHandlerAdapter.class);

    private final List<GatewayFilter> globalFilters;

    private final GatewayLocalCache<List<GatewayFilter>> routerGatewayFilterCache;

    private final AtomicBoolean cacheUpdating = new AtomicBoolean(false);

    public RouteFilterHandlerAdapter(List<GlobalFilter> globalFilters, long cacheMinute) {
        this.globalFilters = loadFilters(globalFilters);
        this.routerGatewayFilterCache = new GatewayLocalCache<>(cacheMinute);
    }

    private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
        return filters.stream().map(GatewayFilterAdapter::new).collect(Collectors.toList());
    }

    @Override
    public boolean supports(Object handler) {
        return Router.class.isAssignableFrom(handler.getClass());
    }

    @NotNull
    @Override
    public Mono<HandlerResult> handle(@NotNull ServerWebExchange exchange, @NotNull Object handler) {

        Router matchedRouter = (Router) handler;

        List<GatewayFilter> gatewayFilters = getRouterFilterList(matchedRouter);
        if (logger.isDebugEnabled()) {
            logger.debug("Sorted gatewayFilterFactories: {}", gatewayFilters);
        }
        exchange.getResponse().setStatusCode(HttpStatus.OK);
        Mono<Void> mono = exchange.getResponse().setComplete();

        // return new DefaultGatewayFilterChain(gatewayFilters).filter(exchange).then(Mono.empty());
        return mono.then(Mono.empty());
    }

    private List<GatewayFilter> getRouterFilterList(Router router) {

        List<GatewayFilter> cachedGatewayFilters = routerGatewayFilterCache.get(router.getId());
        if (cachedGatewayFilters != null && cachedGatewayFilters.isEmpty()) {
            return cachedGatewayFilters;
        }
        // 由于同一个router多次构建的结果是一致的, 这里暂不加入并发写入的控制逻辑
        List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
        combined.addAll(router.getFilters());
        AnnotationAwareOrderComparator.sort(combined);

        if (cacheUpdating.compareAndSet(false, true)) {
            routerGatewayFilterCache.set(router.getId(), combined);
        }
        return combined;
    }
}
